package cz.muni.fi.pa165.sme.services.impl;

import java.util.ArrayList;
import java.util.List;

import cz.muni.fi.pa165.sme.api.BurnedCaloriesService;
import cz.muni.fi.pa165.sme.api.to.BurnedCaloriesTO;
import cz.muni.fi.pa165.sme.api.to.SportActivityTO;
import cz.muni.fi.pa165.sme.common.TOValidator;
import cz.muni.fi.pa165.sme.dao.api.BurnedCaloriesDao;
import cz.muni.fi.pa165.sme.dao.entity.BurnedCalories;
import cz.muni.fi.pa165.sme.dao.entity.SportActivity;
import cz.muni.fi.pa165.sme.exceptions.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.convert.ConversionService;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author amruz
 */
@Service
public class BurnedCaloriesServiceImpl implements BurnedCaloriesService {

	private static final String NULL_OBJECT_MESSAGE = "Parameter cannot be null";
	private static final String ID_NULL = "Id cannot be null";
	private static final String ID_NOT_NULL = "Id must not be set";

	@Autowired
	@Qualifier("conversionService")
	private ConversionService conversionService;

	@Autowired
	private BurnedCaloriesDao burnedCaloriesDao;

//	@Secured(value = "hasRole('ADMIN')")
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	@Override
	@PreAuthorize("hasRole('USER')")
	public void createBurnedCalories(final BurnedCaloriesTO burnedCalories) {
		TOValidator.validateObjectNotNull(burnedCalories, NULL_OBJECT_MESSAGE);
		TOValidator.validateIdNull(burnedCalories.getId(), ID_NOT_NULL);
		final BurnedCalories burnedRecord = conversionService.convert(burnedCalories, BurnedCalories.class);
		burnedCaloriesDao.createBurnedCalories(burnedRecord);
		if (burnedRecord.getId() == null) {
			throw new ServiceException("ID was not assigned");
		}
		burnedCalories.setId(burnedRecord.getId());
	}

//	@Secured(value = "hasRole('ADMIN')")
	@Override
	@PreAuthorize("hasRole('USER')")
	public void deleteBurnedCalories(final BurnedCaloriesTO burnedCalories) {
		TOValidator.validateObjectNotNull(burnedCalories, NULL_OBJECT_MESSAGE);
		TOValidator.validateObjectNotNull(burnedCalories.getId(), ID_NULL);
		final BurnedCalories burnedRecord = conversionService.convert(burnedCalories, BurnedCalories.class);
		burnedCaloriesDao.deleteBurnedCalories(burnedRecord);
	}

//	@Secured(value = "hasRole('ADMIN')")
	@Override
	@PreAuthorize("hasRole('USER')")
	public void updateBurnedCalories(final BurnedCaloriesTO burnedCalories) {
		TOValidator.validateObjectNotNull(burnedCalories, NULL_OBJECT_MESSAGE);
		TOValidator.validateObjectNotNull(burnedCalories.getId(), ID_NULL);
		final BurnedCalories burnedRecord = conversionService.convert(burnedCalories, BurnedCalories.class);
		burnedCaloriesDao.updateBurnedCalories(burnedRecord);
	}

	@Override
	@PreAuthorize("hasRole('USER')")
	public BurnedCaloriesTO findBurnedCalories(final Long id) {
		TOValidator.validateObjectNotNull(id, NULL_OBJECT_MESSAGE);
		final BurnedCalories burnedRecord = burnedCaloriesDao.findBurnedCalories(id);
		return conversionService.convert(burnedRecord, BurnedCaloriesTO.class);
	}

	@Override
	@PreAuthorize("hasRole('USER')")
	public List<BurnedCaloriesTO> findBurnedCaloriesHigherThenCalories(final Long calories) {
		TOValidator.validateObjectNotNull(calories, NULL_OBJECT_MESSAGE);
		final List<BurnedCalories> burnedRecords = burnedCaloriesDao.findBurnedCaloriesHigherThenCalories(calories);
		return convertBurnedCalories(burnedRecords);
	}

	@Override
	@PreAuthorize("hasRole('USER')")
	public List<BurnedCaloriesTO> findAllBurnedCaloriesBySportActivity(final SportActivityTO sportActivity) {
		TOValidator.validateObjectNotNull(sportActivity, NULL_OBJECT_MESSAGE);
		TOValidator.validateObjectNotNull(sportActivity.getId(), ID_NULL);
		final SportActivity activity = conversionService.convert(sportActivity, SportActivity.class);
		final List<BurnedCalories> burnedRecords = burnedCaloriesDao.findAllBurnedCaloriesBySportActivity(activity);
		return convertBurnedCalories(burnedRecords);
	}

	@Override
	@PreAuthorize("hasRole('USER')")
	public List<BurnedCaloriesTO> findAllBurnedCalories() {
		final List<BurnedCalories> burnedRecords = burnedCaloriesDao.findAllBurnedCalories();
		return convertBurnedCalories(burnedRecords);
	}

	@Override
	public boolean exists(final BurnedCaloriesTO burnedCaloriesTO) {
		TOValidator.validateObjectNotNull(burnedCaloriesTO, NULL_OBJECT_MESSAGE);
		final Long id = burnedCaloriesTO.getId();

		return id != null && burnedCaloriesDao.findBurnedCalories(id) != null;
	}

	private List<BurnedCaloriesTO> convertBurnedCalories(final List<BurnedCalories> source) {
		if (source == null) {
			return null;
		}

		final List<BurnedCaloriesTO> target = new ArrayList<BurnedCaloriesTO>(source.size());

		for (BurnedCalories burnedRecord : source) {
			target.add(conversionService.convert(burnedRecord, BurnedCaloriesTO.class));
		}

		return target;
	}
}
